home *** CD-ROM | disk | FTP | other *** search
/ InfoMagic Internet Tools 1995 April / Internet Tools.iso / x25 / nrs.shar.Z / nrs.shar / main.c < prev    next >
Encoding:
C/C++ Source or Header  |  1990-04-27  |  15.7 KB  |  672 lines

  1. # ifndef lint
  2. static char RCSid[]="@(#)$Header: main.c,v 3.6 88/09/08 17:39:05 pb Exp $";
  3. # endif
  4.  
  5. /***********************************************************************\
  6. *                                     *
  7. * This program is responsible for reading a config file,        *
  8. * scurrying about like a whirling dervish amongst numerous        *
  9. * files, and outputing a load of names in some desired format.        *
  10. *                                     *
  11. * Copyright 1986, Piete Brooks, Julian Onions & Adrian Pell        *
  12. * pb@cl.cam.ac.uk, jpo@hcig.nott.ac.uk, Adrian.R.Pell@reading.ac.uk    *
  13. *                                    *
  14. * This program may be copied as long as you don't remove this notice,    *
  15. * try to make any money off of it, or pretend that you wrote it.    *
  16. *                                     *
  17. \***********************************************************************/
  18.  
  19. #include "nrs.h"
  20. #ifdef    USE_UNAME
  21. # include <sys/utsname.h>
  22. #endif    USE_UNAME
  23.  
  24. static_f void initderfil();
  25. static_f void init_files();
  26. static_f void m3process();
  27. static_f void m2process();
  28. static_f void domainprocess();
  29. static_f void init();
  30. static_f void tripcheck();
  31. static_f void checkatomicfiles();
  32. static_f void print_rec();
  33.  
  34. void
  35. main(argc,argv)
  36. int argc;
  37. char    **argv;
  38. {
  39. #ifdef    USE_GETHOSTNAME
  40.     char    buffer[64];
  41.  
  42.     setlinebuf(stderr);
  43. #endif    USE_GETHOSTNAME
  44. #ifdef    USE_UNAME
  45.     struct utsname  utsname;
  46. #endif    USE_UNAME
  47.  
  48.     invo_name = *argv;
  49.     VOID fclose(stdin);        /* we need every fd we can get! */
  50.     if( argc > 1)
  51.         config(++argv, argc - 1);
  52.     else    fatal0("I need a config file buddy!");
  53.  
  54. #ifdef    USE_GETHOSTNAME
  55.     if( hostname == NULL)
  56.     {    VOID gethostname(buffer, sizeof(buffer) - 1);
  57.         hostname = strdup(buffer);
  58.     }
  59. #endif    USE_GETHOSTNAME
  60.  
  61. #ifdef    USE_UNAME
  62.     if( hostname == NULL)
  63.     {    uname (&utsname);
  64.         hostname = utsname.nodename;
  65.     }
  66. #endif    USE_UNAME
  67.  
  68.     if (usederfil)
  69.         initderfil();    /* read in the derived file */
  70.     else
  71.         init_files();    /* read in the files etc. */
  72.     if( forwrev == REVERSE )
  73.         m3process();
  74.     else
  75.     {    m2process();    /* and off we go!    */
  76.         if (DOMfile && outputdomain)
  77.             domainprocess(); /* process the domains */
  78.     }
  79.     exit(exit_rc(0));
  80. }
  81.  
  82. static_f void
  83. init_files()    /* read in files, building up indexs */
  84. {
  85.     Table    *tp;
  86.  
  87.     if( ! M2file )
  88.         M2file = getfpath(MOD2);
  89.     init(M2file, &Module2, FALSE);    /* module 2 file */
  90.     if( forwrev == REVERSE )
  91.     {
  92.         if( ! M3file )
  93.             M3file = getfpath(MOD3);
  94.         init(M3file, &Module3, FALSE);
  95.     }
  96.     if( ! M4file )
  97.         M4file = getfpath(MOD4);
  98.     init(M4file, &Module4, FALSE);    /* module 4 file */
  99. /* now cycle though our list of atomic files got from config */
  100.     for( tp = tablist; tp->T_name != 0; tp++) 
  101.     {
  102.         init(tp->T_name, &tp->hdr, GETFNUMBER);
  103.         max_fnumb = max(max_fnumb, tp->hdr.fnumber);
  104.     }
  105.     if (DOMfile) init(DOMfile, &Domains, FALSE);
  106. }
  107.  
  108. static_f void
  109. initderfil()
  110. {
  111.     FILE    *fp;
  112.     int    ntriples, i;
  113.  
  114.     if (Derfile)
  115.         fp = getfp(Derfile, "r");    /* get file pointer */
  116.     else    /* Try the two defaults */
  117.     {    Derfile = getfpath(DERFIL_D1);
  118.         if (!(fp = getfp(Derfile, "Sr")))
  119.         {    Derfile = getfpath(DERFIL_D2);
  120.             if (!(fp = getfp(Derfile, "Sr")))
  121.             {    Derfile = getfpath(DERFIL_D1);
  122.                 /* GENERATE ERROR */
  123.                 fp = getfp(Derfile, "r");
  124.             }
  125.         }
  126.     }
  127.     i = getint(fp, 5);        /* how big is header? */
  128.     ntriples = getint(fp, 5);    /* should be one less */
  129.     if (ntriples != i-1)
  130.         fatal2("bad derived file -- %d triples instead of %d",
  131.             ntriples, i-1);
  132.     i = getint(fp, 5);        /* offset to Module 2 */
  133.     i = getint(fp, 5);        /* offset to Module 3 */
  134.     i = getint(fp, 5);        /* offset to Module 4 */
  135.     i = getint(fp, 5);        /* offset to wildcard file */
  136.     consistant(fp, Derfile);    /* record version */
  137.     skipnl(fp);
  138.  
  139.     for (i=1; i <= ntriples; i++)
  140.         tripcheck(fp);        /* record info about triples */
  141.     
  142.     checkatomicfiles();        /* do all required contexts exist? */
  143.  
  144.     /* now initialise details of all sub-files */
  145.     M2file = Derfile;
  146.     init(M2file, &Module2, FALSE);
  147.     M3file = Derfile;
  148.     init(M3file, &Module3, FALSE);
  149.     M4file = Derfile;
  150.     init(M4file, &Module4, FALSE);
  151.  
  152.     for (i=1; i <= ntriples; i++)
  153.         init(Derfile, (Header *) 0, SEEKFNUMBER|GETFNUMBER);
  154.  
  155.     /* If anything given, use Derfil */
  156.     if (DOMfile)    DOMfile = Derfile;
  157.  
  158.     init(Derfile, &Domains, FALSE);
  159. }
  160.  
  161. #ifndef    findtriple
  162. Header *
  163. findtriple(fnumber)
  164. int fnumber;
  165. {    Table *tp;
  166.     for (tp = tablist; tp < &tablist[MAXTABLES]; tp++)
  167.         if (tp->hdr.fnumber == fnumber)    return &tp->hdr;
  168.     return NULL;
  169. }
  170. #endif    findtriple
  171.  
  172. static_f void
  173. init(fname, mp, flag)    /* open file - build seek index etc */
  174. char    *fname;
  175. Header    *mp;
  176. int    flag;
  177. {    static    fnumber = 1;
  178.     int    nlines;
  179.     int    i;
  180.     FILE    *fp;
  181.  
  182.     fp = getfp(fname, "r");
  183.     nlines = getint(fp, 5);
  184.     if( flag & GETFNUMBER)        /* this file has a file number */
  185.         fnumber = getint(fp, 5);
  186.     else fnumber++;
  187.     consistant(fp, fname);    /* check all files are from the
  188.                        same batch    */
  189.     skipnl(fp);
  190.  
  191.     if (flag & SEEKFNUMBER) {
  192.         if ((mp = findtriple(fnumber)) == NULL) {
  193.             for (i = 1; i < nlines; i++)
  194.                 skipnl(fp);
  195.             return;
  196.         }
  197.     }
  198.     mp->H_nlines = nlines;
  199.     mp->fnumber = fnumber;
  200.  
  201.     /* malloc ourselves a seek table */
  202.     mp->offset = (long *) calloc((unsigned) (mp->H_nlines+1),
  203.         (unsigned) sizeof(off_t));
  204.     if( mp->offset == NULL)
  205.         fatal2("Out of memory (%d*%d bytes)", mp->H_nlines, sizeof(off_t));
  206.     mp->offset[0] = mp->offset[1] = 0;
  207.  
  208.     /* now build the seek table */
  209.     for( i = 2; i <= mp->H_nlines; i++)
  210.     {
  211.         mp->offset[i] = ftell(fp);
  212.         skipnl(fp);
  213.     }
  214.     vprintf3(1, "read %4d lines of section %2d from %s\n",
  215.             mp->H_nlines, mp->fnumber, fname);
  216. }
  217.  
  218. static_f void
  219. tripcheck(fp)
  220. FILE *fp;
  221. {
  222.     int    context, subnet, direction, thisf;
  223.  
  224.     context   = getint(fp, 5);
  225.     subnet    = getint(fp, 5);
  226.     direction = getint(fp, 5);
  227.     thisf     = getint(fp, 5);
  228.     if (trip2fnumb[context][subnet][direction])
  229.         warn3(1, "Duplicate files %d and %d for context %d",
  230.             thisf, trip2fnumb[context][subnet][direction],
  231.             context);
  232.     else    trip2fnumb[context][subnet][direction] = thisf;
  233.  
  234.     fnumb = max(fnumb, thisf);
  235.     if (thisf < MAX_FNUMB)
  236.     {    fnumb2trip[thisf].f_cont    = context;
  237.         fnumb2trip[thisf].f_subn    = subnet;
  238.         fnumb2trip[thisf].f_dirn    = direction;
  239.         fnumb2trip[thisf].f_tp        = (struct Table *) 0;
  240.     }
  241.  
  242.     skipnl(fp);
  243. }
  244.  
  245. static_f void
  246. checkatomicfiles()
  247. {
  248.     Table    *tp;
  249.  
  250.     for (tp = tablist; tp < &tablist[MAXTABLES]; tp++) if (tp->T_name)
  251.     {    int file = 0;
  252.         int i;
  253.         for (i=0; i < MAX_FNUMB; i++)
  254.             if (fnumb2trip[i].f_cont    == tp->T_context &&
  255.                 fnumb2trip[i].f_subn    == tp->T_network &&
  256.                 fnumb2trip[i].f_dirn    == tp->T_direction)
  257.             {    if (file) warn2(1,
  258.                     "Duplicate files %d and %d", file, i);
  259.                 else    file = i;
  260.             }
  261.  
  262.         if (file && !fnumb2trip[file].f_tp)
  263.         {    tp->hdr.fnumber = file;
  264.             tp->T_name = Derfile;
  265.             cont_want[tp->T_context]++;
  266.             if (file < MAX_FNUMB)
  267.                 fnumb2trip[file].f_tp = tp;
  268.             max_fnumb = max(max_fnumb, file);
  269.         }
  270.         else
  271.         {    char *context  = vlookup(tp->T_context, contexts);
  272.             char *network  = vlookup(tp->T_network, netnames);
  273.             char *direction= vlookup(tp->T_direction, directions);
  274.  
  275.             warn3(1, (file) ?
  276.                 "Duplicate requests for %s-%s-%s" :
  277.                 "Couldn't find %s-%s-%s",
  278.                 context, network, direction);
  279.             tp->T_name = NULL;
  280.         }
  281.     }
  282. }
  283.  
  284. static_f void
  285. m2process() /* Your wish is my command */
  286. {
  287.     Mod2    *m2p;
  288.     Mod4    *m4p;
  289.     Mod2    longname;    /* These are NOT pointers, as getm2rec */
  290.     Mod2    shortname;    /* uses a built in static Mos2 */
  291.     int    i;
  292.     
  293.     for( i = 2; i <= Module2.H_nlines; i++)    /* grap all relevant data */
  294.     {
  295.         if((m2p = getm2rec(i)) == NULL)
  296.         {    warn1(100, "problem on getm2rec rec %d", i);
  297.             continue;
  298.         }
  299.         if( m2p->ls == SHORT )
  300.             continue;
  301.         longname = *m2p;
  302.         if (longname.ls_disp)
  303.         {    if((m2p = getm2rec(longname.ls_disp)) == NULL)
  304.             {    warn1(100,
  305.                 "Can't find corresponding short entry for %s",
  306.                     longname.name);
  307.                 continue;
  308.             }
  309.             shortname = *m2p;
  310.             m2p = &shortname;
  311.         }
  312.         else    m2p = NULL;
  313.  
  314.         if((m4p = getm4rec(longname.index_disp)) == NULL)
  315.         {    warn1(100, "problem on getm4rec rec %d", i);
  316.             continue;
  317.         }
  318.  
  319.         /* if there is an m4 routine, call it. */
  320.         if (!  outputm4rec ||
  321.             !(*outputm4rec)(m4p, m2p, &longname, (Mod3 *) 0))
  322.         {    int j;
  323.             for( j = 0; j < m4p->nquads; j++)
  324.                 if (m4p->quads[j].fnumb <= max_fnumb)
  325.                 {    Atomic    *ap;
  326.                 if(( ap = getatrec(&(m4p->quads[j]),
  327.                     (m2p) ? m2p : &longname)) == NULL)
  328.                     continue;
  329.                 vprintf2(4, "[so `%s|%s']\n", longname.name,
  330.                     (m2p && m2p->name) ? m2p->name : "<unset>");
  331.                 (*outputformat)(&longname, m2p, ap, (Mod3 *) 0);
  332.                 }
  333.         }
  334.     }
  335. }
  336.  
  337. static_f void
  338. m3process() /* Your wish is my command */
  339. {
  340.     Mod2    *m2p;
  341.     Mod3    *m3p;
  342.     Mod2    longname;
  343.     Mod2    shortname;
  344.     int    i;
  345.     
  346.     for( i = 2; i <= Module3.H_nlines; i++)    /* grap all relevant data */
  347.     {
  348.         if((m3p = getm3rec(i)) == NULL)
  349.         {    warn1(100, "problem on getm3rec rec %d", i);
  350.             continue;
  351.         }
  352.         /* Check we want this context ?? */
  353.         if (!cont_want[m3p->m3_context]) continue;
  354.         /* Check we want this context ?? */
  355.         if((m2p = getm2rec(m3p->l_disp)) == NULL)
  356.         {    warn1(100, "problem on getm2rec %d", m3p->l_disp);
  357.             continue;
  358.         }
  359.         longname = *m2p;
  360.         if (longname.ls_disp) {
  361.             if((m2p = getm2rec(longname.ls_disp)) == NULL)
  362.             {    warn1(100,
  363.                 "Can't find corresponding short entry for %s",
  364.                     longname.name);
  365.                 continue;
  366.             }
  367.             shortname = *m2p;
  368.             m2p = &shortname;
  369.         }
  370.         else    m2p = NULL;
  371.  
  372.         /* if there is an m4 routine, call it. */
  373.         if (!  outputm4rec ||
  374.             !(*outputm4rec)(0, m2p, &longname, m3p))
  375.         {    int file = trip2fnumb[m3p->m3_context][m3p->m3_network][DIR_FORWARDS];
  376.             if (file && fnumb2trip[file].f_tp)
  377.                 (*outputformat)(&longname, m2p, 0, m3p);
  378.         }
  379.     }
  380. }
  381.  
  382. static_f void
  383. domainprocess()
  384. {    int i, len;
  385.     static    Domain    rec;
  386.     FILE    *fp = getfp(DOMfile, "r");
  387.  
  388.     for( i = 2; i <= Domains.H_nlines; i++)    /* grap all relevant data */
  389.     {
  390.         VOID fseek(fp, Domains.offset[i++], 0);
  391.         len = getint(fp, 2);
  392.         getstr(fp, rec.name, 0, len);
  393.         if( mixlow != MIXED )
  394.             VOID lowerfy(rec.name);    /* junk upper case! */
  395.  
  396.         VOID fseek(fp, Domains.offset[i++], 0);
  397.         len = getint(fp, 2);
  398.         getstr(fp, rec.gateway, 0, len);
  399.         if( mixlow != MIXED )
  400.             VOID lowerfy(rec.gateway);    /* junk upper case! */
  401.  
  402.         VOID fseek(fp, Domains.offset[i], 0);
  403.         rec.n_contexts = getint(fp, 2);
  404.         for (len=0; len < rec.n_contexts; len++)
  405.             rec.contexts[len] = getint(fp, 2);
  406.         VOID (*outputdomain)(&rec);
  407.     }
  408. }
  409.  
  410. Mod2    *getm2rec( record)    /* get a record from module2 file */
  411. int    record;
  412. {
  413.     FILE    *fp = getfp(M2file, "r");
  414.     static    Mod2    rec;
  415.  
  416.     VOID fseek(fp, Module2.offset[record], 0);
  417.     rec.index_disp = getint(fp, 4);    /* index into module4 */
  418.     rec.ls_disp = getint(fp, 4);    /* index into mod2 */
  419.     rec.ls = getint(fp, 1);        /* long/short flag */
  420.     rec.length = getint(fp, 2);    /* number bytes in string */
  421.     getstr(fp, rec.name, 9, rec.length);    /* string */
  422.     if( mixlow != MIXED )
  423.         VOID lowerfy(rec.name);    /* junk upper case! */
  424.     return &rec;
  425. }
  426.  
  427. Mod3    *getm3rec(record)
  428. int    record;
  429. {
  430.     FILE    *fp = getfp(M3file, "r");
  431.     static    Mod3    rec;
  432.     char *p, *q;
  433.  
  434.     VOID fseek(fp, Module3.offset[record], 0);
  435.     rec.m3_context = getint(fp, 4);
  436.     rec.m3_direction = DIR_REVERSE;
  437.     rec.l_disp = getint(fp, 4);
  438.     rec.m3_length = getint(fp, 2);
  439.     getstr(fp, rec.m3_string, 10, rec.m3_length);
  440.     p = rec.m3_string;
  441.     if ((q = index(p, '.')) == NULL)
  442.         return NULL;
  443.     *q = '\0';
  444.     if ((rec.m3_network = slookup(p, netabbrevs)) < 0)
  445.         return NULL;
  446.     *q = '.';
  447. /* ???if( mixlow != MIXED) lowerfy(rec.m3_string); DBM1??? */
  448.     p = q + 1;
  449.     if ((q = index(p, '.')) == NULL) {
  450.         VOID strcpy(rec.m3_dte, p);
  451.         VOID strcpy(rec.m3_ybts, nullstring);
  452.     }
  453.     else {
  454.         *q = '\0';
  455.         VOID strcpy(rec.m3_dte, p);
  456.         VOID strcpy(rec.m3_ybts, q + 1);
  457.         *q = '.';
  458.     }
  459.     return &rec;
  460. }
  461.  
  462. Mod4    *getm4rec(record)    /* get module 4 record */
  463. int    record;
  464. {
  465.     static    Mod4    rec;
  466.     int    i;
  467.     FILE    *fp = getfp(M4file, "r");
  468.  
  469.     VOID fseek( fp, Module4.offset[record], 0);
  470.     rec.nquads = getint(fp, 5);    /* no of quads in record */
  471.     if( rec.nquads > MAXQUADS)
  472.     {    warn2(100, "too many quads (%d) for rec %d",
  473.             rec.nquads, record);
  474.     }
  475.  
  476.     for(i = 0; i < rec.nquads; i++)
  477.     {    int q    = (i > MAXQUADS) ? MAXQUADS : i;
  478.         rec.quads[q].fnumb = getint(fp, 5); /* which atm file*/
  479.         rec.quads[q].ngtwys= getint(fp, 5); /* no. gtwys ????*/
  480.         rec.quads[q].disp  = getint(fp, 5); /* disp in file */
  481.         rec.quads[q].nlines= getint(fp, 5); /* no. lines */
  482.     }
  483.  
  484.     if( rec.nquads > MAXQUADS) rec.nquads = MAXQUADS;
  485.  
  486.     return &rec;
  487. }
  488.  
  489. Mod2    *findm2rec(name)
  490. char *name;
  491. {
  492.     int    low = 2;
  493.     int    high= Module2.H_nlines;
  494.  
  495.     while (low <= high)
  496.     {    int mid = (low+high)/2;
  497.         int comp;
  498.         Mod2    *rec = getm2rec(mid);
  499.         if (!rec) return rec;
  500.  
  501.         comp = strcmp(name, rec->name);
  502.         if (comp == 0)    return rec;
  503.         if (comp >  0) low  = mid+1;
  504.         else           high = mid-1;
  505.     }
  506.     return (Mod2 *) 0;
  507. }
  508.  
  509. /* Just loacte a record .. */
  510. FILE *
  511. locaterec(qp)
  512. Quad    *qp;
  513. {
  514.     FILE    *fp;
  515.     Table    *tp;
  516.     int file = qp->fnumb;
  517.  
  518.     if (file > fnumb) file = 3;
  519.     if(file > max_fnumb )    /* not interested! */
  520.         return (FILE *) 0;
  521.     if((tp = gettab(file)) == NULL)
  522.     {
  523.         vprintf3(6, "can't find table %d(%d,%d)\n",
  524.                 qp->fnumb, qp->disp, qp->nlines);
  525.         return (FILE *) 0;
  526.     }
  527.     /* Anything there ? */
  528.     if (qp->disp == 0 || qp->nlines == 0) return (FILE *) 0;
  529.  
  530.     fp = getfp(tp->T_name,"r"); /* get an lru file desc. */
  531.     VOID fseek(fp, tp->hdr.offset[qp->disp], 0);
  532.  
  533.     return fp;
  534. }
  535.  
  536. Atomic    *getatrec(qp, m2p)    /* read record from atomic files */
  537. Quad    *qp;
  538. Mod2    *m2p;
  539. {
  540.     Table    *tp;
  541.     int    i, len;
  542.     char    string[MAXNAMELEN];
  543.     char    tag[TAGSIZE];
  544.     static    Atomic    ap;
  545.     FILE    *fp;
  546.     int file = qp->fnumb;
  547.  
  548.     if (file > fnumb) file = 3;
  549.  
  550.     fp = locaterec(qp);
  551.  
  552.     if (!fp)    return (Atomic *) 0;
  553.  
  554.     freeoff(&ap);    /* junk previous data */
  555.  
  556.     tp = gettab(file);
  557.     ap.context = tp->T_context;
  558.     ap.network = tp->T_network;
  559.  
  560.     for( i = 1; i <= qp->nlines; i++)
  561.     {
  562.         getstr(fp, tag, 0, 4);    /* the tag field */
  563.         len = getint(fp, 5);    /* length of next field */
  564.         getstr(fp, string, 0, len);    /* the ar/dte/ybts/di(de) */
  565.         if( lexequ(tag, "dt", 2) )
  566.         {    if( ap.dte ) /* its a dte */
  567.             {    print_rec(qp, 0);
  568.                 warn0(100, "already got a dte");
  569.             }
  570.             ap.dte = strdup(string);
  571.         }
  572.         else if( lexequ(tag, "yb", 2) )
  573.         {    if( ap.ybts )
  574.             {    print_rec(qp, 0);
  575.                 warn0(100, "already got a yb");
  576.             }
  577.             ap.ybts = strdup(string);
  578.         }
  579.         else if( lexequ(tag, "ar", 2) )
  580.         {
  581.             if( ++ap.n_relays > MAXAR)
  582.             {    print_rec(qp, 0);
  583.                 warn0(100, "too many application relays");
  584.             }
  585.             /* ??? Should ARs be lowered ? Yes for mail, no x29 */
  586.             else if( mixlow != MIXED)
  587.                 ap.ar[ap.n_relays-1] = strdup(lowerfy(string));
  588.             else    ap.ar[ap.n_relays-1] = strdup(string);
  589.         }
  590.         else if( lexequ(tag, "di", 2) | lexequ(tag, "de", 2) )
  591.         {
  592.             if( ++ap.n_descs > MAXDESC)
  593.             {    print_rec(qp, 0);
  594.                 warn0(100, "too many description lines");
  595.             }
  596.             else ap.desc[ap.n_descs-1] = strdup(string);
  597.         }
  598.         else
  599.         {    print_rec(qp, 0);
  600.             vprintf3(0, "File %d/%d @ %d\n",
  601.                 qp->fnumb, file, qp->disp);
  602.             warn2(100, "unknown line, '%s' '%s'", tag, string);
  603.         }
  604.     }
  605.     
  606.     if (! ap.dte || ! ap.ybts)
  607.     {
  608.       switch(ap.context)
  609.       {
  610.       case DESC:    break;        /* OK to have no DTE ... */
  611.       case YBTS:            /* OK to have no YBTS    */
  612.       case X29:    if (ap.dte) break;
  613.       default:
  614.         {    int level = (ap.dte) ? 2 : 0;
  615.             char *net = vlookup(ap.network, netnames);
  616.             char *con = vlookup(ap.context, contexts);
  617.             print_rec(qp, level);
  618.             vprintf3(level, "%-18s missing items for %s %s",
  619.                     m2p->name,
  620.                     (net) ? net : "<?>",
  621.                     (con) ? con : "<?>");
  622.             if (ap.dte)
  623.                 vprintf1(level, ", dte %s", ap.dte);
  624.             if (ap.ybts)
  625.                 vprintf1(level, ", ybts %s", ap.ybts);
  626.             if (ap.n_relays)
  627.             {    vprintf0(level, ", relay:");
  628.                 for (i=0; i<ap.n_relays; i++)
  629.                     vprintf1(level, " '%s'", ap.ar[i]);
  630.             }
  631.             if (ap.n_descs)
  632.             {    vprintf0(level, ", desc:");
  633.                 for (i=0; i<ap.n_descs; i++)
  634.                     vprintf1(level, " '%s'", ap.desc[i]);
  635.             }
  636.             if (!ap.dte)
  637.             {    vprintf0(level, " -- entry ignored\n");
  638.                 return (Atomic *) 0;
  639.             }
  640.             vprintf0(level, "\n");
  641.         }
  642.       }
  643.       if (!ap.ybts) ap.ybts = nullstring;
  644.       if (!ap.dte ) ap.dte  = nullstring;
  645.     }
  646.     return    ≈
  647. }
  648.  
  649. static_f void
  650. print_rec(qp, level)
  651. Quad    *qp;
  652. int level;
  653. {
  654.     int    i, len;
  655.     char    string[MAXNAMELEN];
  656.     char    tag[TAGSIZE];
  657.     FILE    *fp = locaterec(qp);
  658.  
  659.     if (!fp)
  660.     {
  661.         vprintf0(level, "Couldn't find record\n");    
  662.         return;
  663.     }
  664.  
  665.     for( i = 1; i <= qp->nlines; i++)
  666.     {    getstr(fp, tag, 0, 4);    /* the tag field */
  667.         len = getint(fp, 5);    /* length of next field */
  668.         getstr(fp, string, 0, len);    /* the ar/dte/ybts/di(de) */
  669.         vprintf3(level, "%-4s %2d '%s'\n", tag, len, string);
  670.     }
  671. }
  672.